home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
System Booster
/
System Booster.iso
/
Archives
/
GNU
/
GNUPLOTsrc.lha
/
matrix.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-01-22
|
8KB
|
376 lines
#ifndef lint
static char *RCSid = "$Id: matrix.c,v 1.10 1994/09/13 16:13:49 alex Exp $";
#endif
/*
* Matrix algebra, part of
*
* Nonlinear least squares fit according to the
* Marquardt-Levenberg-algorithm
*
* added as Patch to Gnuplot (v3.2 and higher)
* by Carsten Grammes
* Experimental Physics, University of Saarbruecken, Germany
*
* Internet address: cagr@rz.uni-sb.de
*
* Copyright of this module: Carsten Grammes, 1993
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* This software is provided "as is" without express or implied warranty.
*/
#define MATRIX_MAIN
#include <math.h>
#include "type.h"
#include "fit.h"
#include "matrix.h"
#include "stdfn.h"
/*****************************************************************/
#define Swap(a,b) {double temp=(a); (a)=(b); (b)=temp;}
#define WINZIG 1e-30
/*****************************************************************
internal prototypes
*****************************************************************/
static void lu_decomp __P((double **a, int n, int *indx, double *d));
static void lu_backsubst __P((double **a, int n, int *indx, double b[]));
/*****************************************************************
first straightforward vector and matrix allocation functions
*****************************************************************/
double *vec (n)
int n;
{
/* allocates a double vector with n elements */
double *dp;
if( n < 1 )
return (double *) NULL;
if ( (dp = (double *) malloc ( n * sizeof(double) )) == NULL )
Eex ("Memory running low during fit")
return dp;
}
int *ivec (n)
int n;
{
/* allocates a int vector with n elements */
int *ip;
if( n < 1 )
return (int *) NULL;
if ( (ip = (int *) malloc ( n * sizeof(int) )) == NULL )
Eex ("Memory running low during fit")
return ip;
}
double **matr (rows, cols)
int rows;
int cols;
{
/* allocates a double matrix */
register int i;
register double **m;
if ( rows < 1 || cols < 1 )
return NULL;
/* allocate pointers to rows */
if ( (m = (double **) malloc ( rows * sizeof(double *) )) == NULL )
Eex ("Memory running low during fit")
/* allocate rows and set pointers to them */
for ( i=0 ; i<rows ; i++ )
if ( (m[i] = (double *) malloc (cols * sizeof(double))) == NULL )
Eex ("Memory running low during fit")
return m;
}
void free_matr (m, rows)
double **m;
int rows;
{
register int i;
for ( i=0 ; i<rows ; i++ )
free ( m[i] );
free (m);
}
void redim_vec (v, n)
double **v;
int n;
{
if ( n < 1 ) {
*v = NULL;
return;
}
if ( (*v = (double *) ralloc (*v, n * sizeof(double), NULL))== NULL )
Eex ("Memory running low during fit")
}
void redim_ivec (v, n)
int **v;
int n;
{
if ( n < 1 ) {
*v = NULL;
return;
}
if ( (*v = (int *) ralloc (*v, n * sizeof(int), NULL)) == NULL )
Eex ("Memory running low during fit")
}
/*****************************************************************
Linear equation solution by Gauss-Jordan elimination
*****************************************************************/
void solve (a, n, b, m)
double **a;
int n;
double **b;
int m;
{
int *c_ix, *r_ix, *pivot_ix, *ipj, *ipk,
i, ic, ir, j, k, l, s;
double large, dummy, tmp, recpiv,
**ar, **rp,
*ac, *cp, *aic, *bic;
c_ix = ivec (n);
r_ix = ivec (n);
pivot_ix = ivec (n);
memset (pivot_ix, 0, n*sizeof(int));
for ( i=0 ; i<n ; i++ ) {
large = 0.0;
ipj = pivot_ix;
ar = a;
for ( j=0 ; j<n ; j++, ipj++, ar++ )
if (*ipj != 1) {
ipk = pivot_ix;
ac = *ar;
for ( k=0 ; k<n ; k++, ipk++, ac++ )
if ( *ipk ) {
if ( *ipk > 1 )
Eex ("Singular matrix")
}
else {
if ( (tmp = fabs(*ac)) >= large ) {
large = tmp;
ir = j;
ic = k;
}
}
}
++(pivot_ix[ic]);
if ( ic != ir ) {
ac = b[ir];
cp = b[ic];
for ( l=0 ; l<m ; l++, ac++, cp++ )
Swap(*ac, *cp)
ac = a[ir];
cp = a[ic];
for ( l=0 ; l<n ; l++, ac++, cp++ )
Swap(*ac, *cp)
}
c_ix[i] = ic;
r_ix[i] = ir;
if ( *(cp = &(a[ic][ic])) == 0.0 )
Eex ("Singular matrix")
recpiv = 1/(*cp);
*cp = 1;
cp = b[ic];
for ( l=0 ; l<m ; l++ )
*cp++ *= recpiv;
cp = a[ic];
for ( l=0 ; l<n ; l++ )
*cp++ *= recpiv;
ar = a;
rp = b;
for ( s=0 ; s<n ; s++, ar++, rp++ )
if ( s != ic ) {
dummy = (*ar)[ic];
(*ar)[ic] = 0;
ac = *ar;
aic = a[ic];
for ( l=0 ; l<n ; l++ )
*ac++ -= *aic++ * dummy;
cp = *rp;
bic = b[ic];
for ( l=0 ; l<m ; l++ )
*cp++ -= *bic++ * dummy;
}
}
for ( l=n-1 ; l>=0 ; l-- )
if ( r_ix[l] != c_ix[l] )
for ( ar=a, k=0 ; k<n ; k++, ar++ )
Swap ((*ar)[r_ix[l]], (*ar)[c_ix[l]])
free (pivot_ix);
free (r_ix);
free (c_ix);
}
/*****************************************************************
LU-Decomposition of a quadratic matrix
*****************************************************************/
static void lu_decomp (a, n, indx, d)
double **a;
int n;
int *indx;
double *d;
{
int i, imax, j, k;
double large, dummy, temp,
**ar, **lim,
*limc, *ac, *dp, *vscal;
dp = vscal = vec (n);
*d = 1.0;
for ( ar=a, lim = &(a[n]) ; ar<lim ; ar++ ) {
large = 0.0;
for ( ac = *ar, limc = &(ac[n]) ; ac<limc ; )
if ( (temp = fabs (*ac++)) > large )
large = temp;
if ( large == 0.0 )
Eex ("Singular matrix in LU-DECOMP")
*dp++ = 1/large;
}
ar = a;
for ( j=0 ; j<n ; j++, ar++ ) {
for ( i=0 ; i<j ; i++ ) {
ac = &(a[i][j]);
for ( k=0 ; k<i ; k++ )
*ac -= a[i][k] * a[k][j];
}
large = 0.0;
dp = &(vscal[j]);
for ( i=j ; i<n ; i++ ) {
ac = &(a[i][j]);
for ( k=0 ; k<j ; k++ )
*ac -= a[i][k] * a[k][j];
if ( (dummy = *dp++ * fabs(*ac)) >= large ) {
large = dummy;
imax = i;
}
}
if ( j != imax ) {
ac = a[imax];
dp = *ar;
for ( k=0 ; k<n ; k++, ac++, dp++ )
Swap (*ac, *dp);
*d = -(*d);
vscal[imax] = vscal[j];
}
indx[j] = imax;
if ( *(dp = &(*ar)[j]) == 0 )
*dp = WINZIG;
if ( j != n-1 ) {
dummy = 1/(*ar)[j];
for ( i=j+1 ; i<n ; i++ )
a[i][j] *= dummy;
}
}
free (vscal);
}
/*****************************************************************
Routine for backsubstitution
*****************************************************************/
static void lu_backsubst (a, n, indx, b)
double **a;
int n;
int *indx;
double b[];
{
int i, memi = -1, ip, j;
double sum, *bp, *bip, **ar, *ac;
ar = a;
for ( i=0 ; i<n ; i++, ar++ ) {
ip = indx[i];
sum = b[ip];
b[ip] = b[i];
if (memi >= 0) {
ac = &((*ar)[memi]);
bp = &(b[memi]);
for ( j=memi ; j<=i-1 ; j++ )
sum -= *ac++ * *bp++;
}
else
if ( sum )
memi = i;
b[i] = sum;
}
ar--;
for ( i=n-1 ; i>=0 ; i-- ) {
ac = &(*ar)[i+1];
bp = &(b[i+1]);
bip = &(b[i]);
for ( j=i+1 ; j<n ; j++ )
*bip -= *ac++ * *bp++;
*bip /= (*ar--)[i];
}
}
/*****************************************************************
matrix inversion
*****************************************************************/
void inverse (src, dst, n)
double **src;
double **dst;
int n;
{
int i,j;
int *indx;
double d, *col, **tmp;
indx = ivec (n);
col = vec (n);
tmp = matr (n, n);
for ( i=0 ; i<n ; i++ )
memcpy (tmp[i], src[i], n*sizeof(double));
lu_decomp (tmp, n, indx, &d);
for ( j=0 ; j<n ; j++ ) {
for ( i=0 ; i<n ; i++ )
col[i] = 0;
col[j] = 1;
lu_backsubst (tmp, n, indx, col);
for ( i=0 ; i<n ; i++ )
dst[i][j] = col[i];
}
free (indx);
free (col);
free_matr (tmp, n);
}